package com.feeyo.prophet.actions.flight;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.feeyo.llm.agent.engine.*;
import com.feeyo.llm.util.JsonUtil;
import com.feeyo.prophet.plugins.FlightScheduleActionUtils;
import com.feeyo.prophet.pojo.action.financial.FinancialReportResp;
import com.feeyo.prophet.pojo.action.flight.FinancialReport;
import com.feeyo.prophet.pojo.action.functioncall.flight.FinancialReportProperties;
import com.feeyo.prophet.pojo.action.functioncall.FunctionCall;
import com.feeyo.prophet.pojo.action.functioncall.ItemsBean;
import com.feeyo.prophet.pojo.action.functioncall.flight.common.BasicTypeDefaultList;
import com.feeyo.prophet.config.ParametersSingletonManager;
import com.feeyo.prophet.plugins.AnswerUtils;
import com.feeyo.prophet.plugins.DbSearchActionUtils;
import com.google.common.collect.Lists;
import io.micrometer.common.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.jetbrains.annotations.Nullable;
import org.springframework.http.HttpStatus;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * 财报统计Action, 同比环比
 * 1. 东航2023年营业收入,营业成本,研发费用,销售费用是多少?
 * 2. 东航2021年营业收入,营业成本,研发费用,销售费用 同比2019年变化了多少
 * <p>
 * 3. 广州白云机场2021年管理费用,财富费用,营业利润 是多少
 * 4. 广州白云机场2021年管理费用,财富费用,营业利润 同比2019年变化了多少
 *
 * @author lihu
 */
@Slf4j
public class FinancialReportAction implements Action {

    /**
     * 定义机场list
     */
    private static final List<String> AIRLINE_LIST = new ArrayList<>(List.of("东航", "华夏", "南航", "吉祥", "国航", "山航", "春秋", "海航"));
    /**
     * 定义航司list
     */
    private static final List<String> AIRPORT_LIST = new ArrayList<>(List.of("上海机场", "厦门机场", "广州白云", "深圳机场", "美兰空港", "首都股份"));

    private final String host;
    private final Integer port;

    public FinancialReportAction(String host, Integer port) {
        this.host = host;
        this.port = port;
    }

    @Override
    public String human() {
        return "航司,机场财务问题";
    }

    @Override
    public String name() {
        return "FinancialReportAction";
    }

    @Override
    public String eg() {
        return """
                Question: 广州白云机场2021年管理费用,财富费用,营业利润
                Thought: 我应该使用FinancialReportAction搜索工具来查找航司财务信息
                Action: FinancialReportAction
                Action Input: {"yeal":"2021", "airports":["广州白云"] "language":"中文"}
                """;
    }

    @Override
    public String description() {
        return """
                用于查询指定航司所属年份的财务信息或者指定机场所属年份的财务信息。具体为：
                  1. 指定航司，指定时间范围。查询:营业收入,营业成本,研发费用,销售费用,管理费用,财富费用,营业利润,营业支出,净利润,收益
                  2. 指定机场，指定时间范围。查询:营业收入,营业成本,研发费用,销售费用,管理费用,财富费用,营业利润,营业支出,净利润,收益
                """;
    }

    @Override
    public String parameters() {
        String parameters = ParametersSingletonManager.getParameters("FinancialReportAction", () -> {
            FunctionCall functionCall = new FunctionCall();
            functionCall.setType("object");
            functionCall.setRequired(Lists.newArrayList("year", "fields"));
            FinancialReportProperties properties = new FinancialReportProperties();
            properties.setYear(new BasicTypeDefaultList("string", "查询年份，格式: yyyy，例如: '2024'"));
            properties.setAirlines(new BasicTypeDefaultList("array", "航空公司集合，使用中文名称，例如: ['东航']", new ItemsBean("string", Lists.newArrayList("东航", "华夏", "南航", "吉祥", "国航", "山航", "春秋", "海航"), null, null), new ArrayList<>()));
            properties.setAirports(new BasicTypeDefaultList("array", "机场集合，使用中文名称，例如: ['上海机场']", new ItemsBean("string", Lists.newArrayList("上海机场", "厦门机场", "广州白云", "深圳机场", "美兰空港", "首都股份"), null, null), new ArrayList<>()));
            List<ResultScheme.ResultAttach> resultAttachList = result().getResultAttachList();
            List<String> fieldsList = resultAttachList.stream().map(ResultScheme.ResultAttach::getName).toList();
            // 修改 fields 部分，确保生成正确的字段列表
            properties.setFields(new BasicTypeDefaultList("array", "返回结果字段集合(根据需要多选), 各个字段含义解释如下: " + JsonUtil.marshalToString(resultAttachList)
                    + "。可选填字段如下: " + String.join(", ", fieldsList) + ",你需要尽量全面的选出适用字段。可以选多，不要选少。", new ItemsBean("string"), 1));
            functionCall.setProperties(properties);
            return functionCall.toString();
        });
        return parameters;
    }

    @Override
    public ParameterScheme defaultParameters() {
        Map<String, ParameterScheme.Property> properties = new HashMap<>();
        ParameterScheme.Property yearProperty = new ParameterScheme.Property();
        yearProperty.setType("string");
        yearProperty.setDescription("查询年份，格式: yyyy，例如: '2024'");
        properties.put("year", yearProperty);
        ParameterScheme.Property airlinesProperty = new ParameterScheme.Property();
        airlinesProperty.setType("array");
        airlinesProperty.setDescription("航空公司集合，例如: ['东航']");
        ParameterScheme.Property.Items airlinesItems = new ParameterScheme.Property.Items();
        airlinesItems.setType("string");
        airlinesItems.setEnums(List.of("东航", "华夏", "南航", "吉祥", "国航", "山航", "春秋", "海航"));
        airlinesProperty.setItems(airlinesItems);
        properties.put("airlines", airlinesProperty);
        ParameterScheme.Property airportsProperty = new ParameterScheme.Property();
        airportsProperty.setType("array");
        airportsProperty.setDescription("机场集合，例如: ['上海机场']");
        ParameterScheme.Property.Items airportsItems = new ParameterScheme.Property.Items();
        airportsItems.setType("string");
        airportsItems.setEnums(List.of("上海机场", "厦门机场", "广州白云", "深圳机场", "美兰空港", "首都股份"));
        airportsProperty.setItems(airportsItems);
        properties.put("airports", airportsProperty);
        List<ResultScheme.ResultAttach> resultAttachList = result().getResultAttachList();
        List<String> fieldsList = resultAttachList.stream().map(ResultScheme.ResultAttach::getName).collect(Collectors.toList());
        ParameterScheme.Property fieldsProperty = new ParameterScheme.Property();
        fieldsProperty.setType("array");
        fieldsProperty.setDescription("返回结果字段集合(根据需要多选), 字段含义: " + JsonUtil.marshalToString(resultAttachList)
                + "，可选字段: " + String.join(", ", fieldsList));
        ParameterScheme.Property.Items fieldsItems = new ParameterScheme.Property.Items();
        fieldsItems.setType("string");
        fieldsProperty.setItems(fieldsItems);
        fieldsProperty.setMinItems(1);
        properties.put("fields", fieldsProperty);
        ParameterScheme parameterScheme = new ParameterScheme("object", List.of("year", "fields"), properties);
        return parameterScheme;
    }

    @Override
    public ResultScheme result() {
        ResultScheme resultScheme = new ResultScheme();
        List<ResultScheme.ResultAttach> resultAttachList = Lists.newArrayList();
        resultAttachList.add(new ResultScheme.ResultAttach("airline", "string", "航司IATA二字码"));
        resultAttachList.add(new ResultScheme.ResultAttach("airport", "string", "机场IATA三字码"));
        resultAttachList.add(new ResultScheme.ResultAttach("period", "string", "数据时期"));
        resultAttachList.add(new ResultScheme.ResultAttach("grossRevenue", "float", "营业总收入,单位亿元"));
        resultAttachList.add(new ResultScheme.ResultAttach("operatingRevenue", "float", "营业收入,单位亿元"));
        resultAttachList.add(new ResultScheme.ResultAttach("totalOperatingCosts", "float", "营业总成本,单位亿元"));
        resultAttachList.add(new ResultScheme.ResultAttach("operatingCosts", "float", "营业成本,单位亿元"));
        resultAttachList.add(new ResultScheme.ResultAttach("rdExpenses", "float", "研发费用,单位亿元"));
        resultAttachList.add(new ResultScheme.ResultAttach("taxesSurcharges", "float", "营业税金及附加,单位亿元"));
        resultAttachList.add(new ResultScheme.ResultAttach("sellingCosts", "float", "销售费用,单位亿元"));
        resultAttachList.add(new ResultScheme.ResultAttach("overhead", "float", "管理费用,单位亿元"));
        resultAttachList.add(new ResultScheme.ResultAttach("financialExpenses", "float", "财务费用,单位亿元"));
        resultAttachList.add(new ResultScheme.ResultAttach("assetsLoss", "float", "资产减值损失,单位亿元"));
        resultAttachList.add(new ResultScheme.ResultAttach("otherOpIncome", "float", "其他经营收益,单位亿元"));
        resultAttachList.add(new ResultScheme.ResultAttach("incomeChangesValue", "float", "公允价值变动收益,单位亿元"));
        resultAttachList.add(new ResultScheme.ResultAttach("investmentIncome", "float", "投资收益,单位亿元"));
        resultAttachList.add(new ResultScheme.ResultAttach("joinCooperativeIncome", "float", "对联营企业和合营企业的投资收益,单位亿元"));
        resultAttachList.add(new ResultScheme.ResultAttach("operatingProfit", "float", "营业利润,单位亿元"));
        resultAttachList.add(new ResultScheme.ResultAttach("nonbusinessIncome", "float", "营业外收入,单位亿元"));
        resultAttachList.add(new ResultScheme.ResultAttach("nonbusinessExpenditure", "float", "营业外支出,单位亿元"));
        resultAttachList.add(new ResultScheme.ResultAttach("totalProfits", "float", "利润总额,单位亿元"));
        resultAttachList.add(new ResultScheme.ResultAttach("taxExpense", "float", "所得税费用,单位亿元"));
        resultAttachList.add(new ResultScheme.ResultAttach("netProfits", "float", "净利润,单位亿元"));
        resultAttachList.add(new ResultScheme.ResultAttach("parentStockholderProfits", "float", "归属于母公司股东的净利润,单位亿元"));
        resultAttachList.add(new ResultScheme.ResultAttach("minorityInterest", "float", "少数股东损益,单位亿元"));
        resultAttachList.add(new ResultScheme.ResultAttach("netProfitLoss", "float", "扣除非经常性损益后的净利润,单位亿元"));
        resultAttachList.add(new ResultScheme.ResultAttach("earningsPerShare", "float", "每股收益,单位元"));
        resultAttachList.add(new ResultScheme.ResultAttach("basicEps", "float", "基本每股收益,单位元"));
        resultAttachList.add(new ResultScheme.ResultAttach("dilutedEps", "float", "稀释每股收益,单位元"));
        resultAttachList.add(new ResultScheme.ResultAttach("otherComprehensiveIncome", "float", "其他综合收益,单位亿元"));
        resultAttachList.add(new ResultScheme.ResultAttach("parentComprehensiveIncome", "float", "归属于母公司股东的其他综合收益,单位亿元"));
        resultAttachList.add(new ResultScheme.ResultAttach("minorityComprehensiveIncome", "float", "归属于少数股东的其他综合收益,单位亿元"));
        resultAttachList.add(new ResultScheme.ResultAttach("totalComprehensiveIncome", "float", "综合收益总额,单位亿元"));
        resultAttachList.add(new ResultScheme.ResultAttach("parentTotalIncome", "float", "归属于母公司所有者的综合收益总额,单位亿元"));
        resultAttachList.add(new ResultScheme.ResultAttach("minorityTotalIncome", "float", "归属于少数股东的综合收益总额,单位亿元"));
        resultAttachList.add(new ResultScheme.ResultAttach("otherIncome", "float", "其他收益,单位亿元"));
        resultAttachList.add(new ResultScheme.ResultAttach("profitLossAnalysis", "string", "盈亏分析"));
        resultAttachList.add(new ResultScheme.ResultAttach("netProfitRatio", "float", "净利率,单位亿元"));
        resultAttachList.add(new ResultScheme.ResultAttach("aviationIncome", "float", "航空性收入占比"));
        resultAttachList.add(new ResultScheme.ResultAttach("airplaneTakeoffCharge", "float", "飞机起降及相关费用,单位亿元"));
        resultAttachList.add(new ResultScheme.ResultAttach("passengerServiceCharge", "float", "旅客服务费用,单位亿元"));
        resultAttachList.add(new ResultScheme.ResultAttach("noAviationIncome", "float", "非航空性收入占比"));
        resultScheme.setResultAttachList(resultAttachList);
        return resultScheme;
    }

    @Override
    public ActionResult run(String question, String input, ExecuteOptions options) throws Exception {
        try {
            FinancialReport req = JSON.parseObject(input, FinancialReport.class);
            List<String> airlines = req.getAirlines();
            List<String> airports = req.getAirports();
            String year = req.getYear();
            boolean isLose = false;
            StringBuilder qSb = new StringBuilder("缺少参数如下:");
            if (StringUtils.isEmpty(year)) {
                qSb.append("查询日期, ");
                isLose = true;
            }
            if (CollectionUtils.isEmpty(airlines) && CollectionUtils.isEmpty(airports)) {
                qSb.append("机场与航司二选一");
                isLose = true;
            }
            if (isLose) {
                qSb.append("必填,请使用 conversation action 让用户补充这些参数");
                return new ActionResult(HttpStatus.BAD_REQUEST.value(), qSb.toString());
            }
            // 做校验
            if (CollectionUtils.isNotEmpty(airlines)) {
                var airlineSb = getActionResult(airlines, AIRLINE_LIST);
                if (airlineSb != null) {
                    return airlineSb;
                }
            }
            if (CollectionUtils.isNotEmpty(airports)) {
                var airportSb = getActionResult(airports, AIRPORT_LIST);
                if (airportSb != null) {
                    return airportSb;
                }
            }
            ResultScheme resultScheme = FlightScheduleActionUtils.resultScheme(req.getFields(), result());
            //机场
            if (CollectionUtils.isNotEmpty(airports)) {
                return airportResult(year, airports, input, resultScheme);
            }
            // 查询航司
            if (CollectionUtils.isNotEmpty(airlines)) {
                return airlineResult(year, airlines, input, resultScheme);
            }
            return new ActionResult( HttpStatus.BAD_REQUEST.value(), "暂不支持该条件查询");
        } catch (Throwable e) {
            log.error("error", e);
            return new ActionResult(HttpStatus.INTERNAL_SERVER_ERROR.value(), "解析发生错误，请思考后再调用？");
        }
    }

    /**
     * 机场,航司校验
     */
    @Nullable
    private ActionResult getActionResult(List<String> dataList, List<String> enumList) {
        StringBuilder airportSb = new StringBuilder();
        for (int i = 0; i < dataList.size(); i++) {
            String data = dataList.get(i);
            if (!enumList.contains(data)) {
                airportSb.append(data).append(",");
            }
        }
        if (StringUtils.isNotEmpty(String.valueOf(airportSb))) {
            return new ActionResult( HttpStatus.BAD_REQUEST.value(), airportSb + "财报数据不存在");
        }
        return null;
    }

    /**
     * 航司查询
     *
     * @param year         时间
     * @param airlineList 航司
     * @param input        输入
     */
    private ActionResult airlineResult(String year, List<String> airlineList, String input, ResultScheme resultScheme) {
        List<FinancialReportResp> financialReportRespList = Lists.newArrayList();
        for (int i = 0; i < airlineList.size(); i++) {
            String airline = airlineList.get(i);
            String respTxt = null;
            try {
                respTxt = DbSearchActionUtils.queryFinancialAirport(host, port, null, airline, year);
            } catch (Exception e) {
                log.error("airportResult error", e);
            }
            if (StringUtils.isEmpty(respTxt)) {
                return new ActionResult( HttpStatus.BAD_REQUEST.value(), "未查询到航司数据");
            }
            JSONObject jsonResp = JSONObject.parseObject(respTxt);
            JSONObject data = jsonResp.getJSONObject("data");
            if (null == data) {
                continue;
            }
            JSONArray row = data.getJSONArray("rows");
            if (null == row) {
                continue;
            }
            if (!row.isEmpty()) {
                for (Object rowData : row) {
                    FinancialReportResp financialReportResp = JSON.parseObject(String.valueOf(rowData), FinancialReportResp.class);
                    financialReportRespList.add(financialReportResp);
                }
            }
        }
        log.info("航司查询结果：{}", JSON.toJSONString(financialReportRespList));
        return AnswerUtils.answer(name(), input, financialReportRespList,resultScheme);
    }

    /**
     * 机场查询
     *
     * @param year         时间
     * @param airportsList 机场名字
     * @param input        输入
     */
    private ActionResult airportResult(String year, List<String> airportsList, String input, ResultScheme resultScheme) {
        List<FinancialReportResp> financialReportRespList = Lists.newArrayList();
        for (int i = 0; i < airportsList.size(); i++) {
            String airport = airportsList.get(i);
            String respTxt = null;
            try {
                respTxt = DbSearchActionUtils.queryFinancialAirport(host, port, airport, null, year);
            } catch (Exception e) {
                log.error("airportResult error", e);
            }
            if (StringUtils.isEmpty(respTxt)) {
                return new ActionResult( HttpStatus.BAD_REQUEST.value(), "未查询到机场数据");
            }
            JSONObject jsonResp = JSONObject.parseObject(respTxt);
            JSONObject data = jsonResp.getJSONObject("data");
            if (null == data) {
                continue;
            }
            JSONArray row = data.getJSONArray("rows");
            if (null == row) {
                continue;
            }
            if (!row.isEmpty()) {
                for (Object rowData : row) {
                    FinancialReportResp financialReportResp = JSON.parseObject(String.valueOf(rowData), FinancialReportResp.class);
                    financialReportRespList.add(financialReportResp);
                }
            }
        }
        log.info("机场查询结果：{}", JSON.toJSONString(financialReportRespList));
        return AnswerUtils.answer(name(), input, financialReportRespList, resultScheme);
    }
}